package user

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"wms/model"

	"wms/internal/svc"
	"wms/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type MenuLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewMenuLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MenuLogic {
	return &MenuLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *MenuLogic) Menu() (resp *types.MenuListResponse, err error) {
	resp = new(types.MenuListResponse)

	uid, err := l.ctx.Value("uid").(json.Number).Int64()
	if err != nil {
		fmt.Printf("[Error]用户id解析:%s\n", err.Error())
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}

	//1.用户是否存在
	_, err = l.svcCtx.UserModel.FindOne(l.ctx, uid)
	switch err {
	case nil: //不处理
	case model.ErrNotFound: //不存在
		resp.Code = http.StatusBadRequest
		resp.Msg = "用户不存在"
		return resp, nil
	default: //其他错误
		fmt.Printf("[Error]查询用户[%d]是否存在:%s\n", uid, err.Error())
		resp.Code = http.StatusInternalServerError
		resp.Msg = "服务内部错误"
		return resp, nil
	}

	//2.查询用户角色
	//userRoles, err := l.svcCtx.UserRoleModel.FindByPage(l.ctx, fmt.Sprintf(" where user_id=%d", uid))
	//if err != nil {
	//	fmt.Printf("[Error]查询用户[%d]角色:%s\n", uid, err.Error())
	//	resp.Code = http.StatusInternalServerError
	//	resp.Msg = "服务内部错误"
	//	return resp, nil
	//}

	//3.根据角色列表查询菜单id列表
	//3.1 用户是超级管理员
	var casbinRoles []string
	var ok bool
	casbinRoles, err = l.svcCtx.Enforcer.GetRolesForUser(fmt.Sprintf("user_%d", uid))
	if len(casbinRoles) == 0 && uid != 1 {
		fmt.Printf("[Error]用户[%d]没有绑定角色\n", uid)
		resp.Code = http.StatusBadRequest
		resp.Msg = "没有访问权限"
		return resp, nil
	}

	for _, role := range casbinRoles {
		if strings.TrimPrefix(role, "role_") == "1" { //是否存在超级管理员
			ok = true
		}
	}

	if ok {
		var menus []model.Menu
		menus, err = l.svcCtx.MenuModel.FindByPage(l.ctx, "")
		if err != nil {
			fmt.Printf("[Error]查询角色[超级管理员]菜单列表:%s\n", err.Error())
			resp.Code = http.StatusInternalServerError
			resp.Msg = "服务内部错误"
			return resp, nil
		}

		for _, menu := range menus {
			var one types.Menu
			one, err = transMenus(menu)
			if err != nil {
				fmt.Printf("[Error]菜单[%s]meta解析失败:%s\n", menu.Path, err.Error())
				resp.Code = http.StatusInternalServerError
				resp.Msg = "服务内部错误"
				return resp, nil
			}

			resp.Data = append(resp.Data, one)
		}

		resp.Code = http.StatusOK
		resp.Msg = "成功"
		return resp, nil
	}

	//3.2 用户不是超级管理员
	var menusId = make(map[int64]struct{})
	var rolesId string
	var query string
	if uid == 1 {
		var menus []model.Menu
		query = " group by menu_id"
		menus, err = l.svcCtx.MenuModel.FindByPage(l.ctx, "")
		if err != nil {
			fmt.Printf("[Error]查询管理员角色的菜单列表:%s\n", err.Error())
			resp.Code = http.StatusInternalServerError
			resp.Msg = "服务内部错误"
			return resp, nil
		}

		for _, menu := range menus {
			menusId[menu.Id] = struct{}{}
		}
	} else {
		var roleMenus []model.RoleMenu
		query = fmt.Sprintf(" where role_id in (%s) group by menu_id", rolesId)
		roleMenus, err = l.svcCtx.RoleMenuModel.FindByPage(l.ctx, query)
		if err != nil {
			fmt.Printf("[Error]查询角色[%s]菜单列表:%s\n", strings.ReplaceAll(strings.Join(casbinRoles, ","), "role_", ""), err.Error())
			resp.Code = http.StatusInternalServerError
			resp.Msg = "服务内部错误"
			return resp, nil
		}

		for _, roleMenu := range roleMenus {
			menusId[roleMenu.MenuId] = struct{}{}
		}
	}

	//4.根据菜单id列表查询菜单列表
	for menuId := range menusId {
		var menu *model.Menu
		menu, err = l.svcCtx.MenuModel.FindOne(l.ctx, menuId)
		switch err {
		case nil:
		case model.ErrNotFound:
			fmt.Printf("[Error]菜单[%d]不存在\n", menuId)
			continue
		default:
			fmt.Printf("[Error]查询菜单[%d]:%s\n", menuId, err.Error())
			resp.Code = http.StatusInternalServerError
			resp.Msg = "服务内部错误"
			return resp, nil
		}

		var one types.Menu
		one, err = transMenus(*menu)
		if err != nil {
			fmt.Printf("[Error]菜单[%s]meta解析失败:%s\n", menu.Path, err.Error())
			resp.Code = http.StatusInternalServerError
			resp.Msg = "服务内部错误"
			return resp, nil
		}

		resp.Data = append(resp.Data, one)
	}

	resp.Code = http.StatusOK
	resp.Msg = "成功"
	return resp, nil
}

func transMenus(m model.Menu) (menus types.Menu, err error) {
	var meta types.Meta
	if err = json.Unmarshal([]byte(m.Meta), &meta); err != nil {
		fmt.Printf("[Error]菜单[%s]meta解析失败:%s\n", m.Path, err.Error())
		return
	}

	menus = types.Menu{
		Id:         m.Id,
		Type:       m.Type,
		SortId:     m.SortId,
		ParentId:   m.ParentId,
		Path:       m.Path,
		Name:       m.Name,
		Component:  m.Component,
		Icon:       meta.Icon,
		Transition: meta.Transition,
		Hidden:     meta.Hidden,
		Fixed:      meta.Fixed,
		Perms:      meta.Perms,
		Remark:     m.Remark,
	}
	return
}
